// 迭代器
class Count {
  constructor(limit) {
    this.count = 1;

    this.limit = limit;
  }

  next() {
    if (this.count <= this.limit) {
      let count = this.count;

      return {
        done: false,
        value: new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(Math.pow(count, 2));
          }, 1000);

          this.count++;
        }),
      };
    } else {
      return { done: true, value: undefined };
    }
  }

  hasNext() {
    return this.count <= this.limit;
  }

  [Symbol.iterator]() {
    return this;
  }
}

// for await 可以对异步迭代器进行遍历，node 版本太低做不了
// for 会先获得 iterator ，然后不停的调用 next 方法 , 然后获得 next 方法 的 value 赋值给 i ，在这个测试用例中 i 是个 promise ，然后使用 await 进行等待执行

(async () => {
  for (const i of new Count(3)) {
    let res = await i;
    console.log(res);
  }
})();

// 本质还得靠 await 实现等待
// 使用循环进行异步迭代
let iterator = new Count(3)[Symbol.iterator](); // 获取自定义对象的迭代器, iterator 就是 Count 的对象

(async function () {
  while (iterator.hasNext()) {
    let res = await iterator.next().value;

    console.log(res);
  }
})();

// 生成器
// * 函数执行后会返回 生成器对应的迭代器，这个迭代器可以供 for ... of 使用
// 通过迭代器不停的返回 promise ，然后 for 之后使用 await 阻塞代码 等待 promise 的 执行 ，这样能够获得 1,4,9 的 值

function get(count) {
  function getDate(index) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(index * index);
      }, 1000);
    });
  }

  return (function* generator(index) {
    if (index > count) {
      return;
    }

    yield getDate(index);

    yield* generator(index + 1);
  })(1);
}

let genObj = get(3);

(async () => {
  for (let i of genObj) {
    let res = await i;

    console.log(res);
  }
})();

// 与上面的不同，自个是利用定时器 定时 next 触发，方面的是for of 循环，再利用 await 阻塞代码，然后触发
// 先通过递归创建3个中断，然后中断后，再利用定时器触发中断
// for ... of 中写 await 是可以阻塞 循环的进行的chuanz
// 这里有个问题，其实 生成器有 4 个 中断，递归产生了 3 个 中断 ，还有一个中断是结束的
// 第一个中断返回的是 undefined ， 接下来的next 传值也是传给这个中断 ， 从这个中断开始往下执行代码，所以 data 能打印出 1来 ，而不是 undefined
// 先传值给中断，再往下执行到中断
{
  let genObj;

  let get = (count) => {
    function getDate(index) {
      setTimeout(() => {
        genObj.next(index * index);
      }, 1000);
    }

    return (function* generator(index) {
      if (index > count) {
        return;
      }

      let data = yield getDate(index);

      console.log(data);

      yield* generator(index + 1);
    })(1);
  };

  genObj = get(3);

  genObj.next();
}
